﻿using NetworkLib.Utilities;
using PBO.Network.Domain;
using PBO.Network.Enumerations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PBO.Network
{
    public class PokemonBattleClient : BattleClient, IBattleClientService
    {
        public PokemonBattleClient(string ip) : base(ip, (int)ServerPort.PokemonBattleServerPort) { }

        #region Events
        public event Action<PlayerMove> OnSetMove;
        public event Action<byte, string, byte[]> OnSetTeam;
        public event Action<string> OnPlayerExit;
        public event Action<string, TieMessage> OnTie;
        public event Action<int> OnSetSeed;
        public event Action<BattleRule[]> OnSetRules;

        public event Action<BattleInfo> OnSetBattleInfo;
        public event Action<BattleSnapshot> OnSetSnapshot;
        public event Action OnRegistObserver;

        public event Action OnLogoned;
        public event Action<string> OnLogonFailed;
        public event Action<string> OnPlayerTimeUp;
        #endregion

        #region Send

        public void SendMove(PlayerMove move)
        {
            base.Send(BattleMethods.SERVER_RECEIVEMOVE_HASH, move);
        }

        public void SendTeam(byte position, string identity, byte[] team)
        {
            var rsp = new BattleTeam();
            rsp.position = position;
            rsp.identity = identity;
            rsp.team = team;
            base.Send(BattleMethods.SERVER_RECEIVETEAM_HASH, rsp);
        }

        public void Exit(string identity)
        {
            base.Send(BattleMethods.SERVER_EXIT_HASH, identity);
        }

        public void Tie(string identity, TieMessage message)
        {
            var rsp = new TieMessageRequest();
            rsp.identity = identity;
            rsp.message = message;
            base.Send(BattleMethods.SERVER_RECEIVETIEMESSAGE_HASH, rsp);
        }

        public void Logon(string identity, BattleMode mode, string versionInfo)
        {
            var rsp = new LogonResponse();
            rsp.identity = identity;
            rsp.modeInfo = mode;
            rsp.versionInfo = versionInfo;
            base.Send(BattleMethods.SERVER_LOGON_HASH, rsp);
        }

        public void RegistObserver(int identity)
        {
            base.Send(BattleMethods.SERVER_REGISTOBSEVER_HASH, identity);
        }

        public void SendBattleInfo(BattleInfo info)
        {
            base.Send(BattleMethods.SERVER_RECEIVEBATTLEINFO_HASH, info);
        }

        public void SendBattleSnapshot(BattleSnapshot snapshot)
        {
            base.Send(BattleMethods.SERVER_RECEIVEBATTLESNAPSHOT_HASH, snapshot);
        }

        public void TimeUp(string identity)
        {
            base.Send(BattleMethods.SERVER_TIMEUP_HASH, identity);
        }

        #endregion

        #region event

        protected void OnLogonSuccess()
        {
            if (OnLogoned != null) OnLogoned();
        }

        protected void OnLogonFail(string message)
        {
            if (OnLogonFailed != null) OnLogonFailed(message);
        }

        protected void OnReceiveRandomSeed(int seed)
        {
            if (OnSetSeed != null) OnSetSeed(seed);
        }

        protected void OnReceiveMove(PlayerMove move)
        {
            if (OnSetMove != null) OnSetMove(move);
        }

        protected void OnReceiveTeam(BattleTeam rsp)
        {
            if (OnSetTeam != null) OnSetTeam(rsp.position, rsp.identity, rsp.team);
        }

        protected void OnReceiveRules(BattleRule[] rules)
        {
            if (OnSetRules != null) OnSetRules(rules);
        }

        protected void OnExit(string identity)
        {
            if (OnPlayerExit != null) OnPlayerExit(identity);
        }

        protected void OnReceiveTieMessage(TieMessageRequest rsp)
        {
            if (OnTie != null) OnTie(rsp.identity, rsp.message);
        }

        protected void OnRegistObsever(int identity)
        {
            if (OnRegistObserver != null) OnRegistObserver();
        }

        protected void OnReceiveBattleInfo(BattleInfo info)
        {
            if (OnSetBattleInfo != null) OnSetBattleInfo(info);
        }

        protected void OnReceiveBattleSnapshot(BattleSnapshot snapshot)
        {
            if (OnSetSnapshot != null) OnSetSnapshot(snapshot);
        }

        protected void OnTimeUp(string identity)
        {
            if (OnPlayerTimeUp != null) OnPlayerTimeUp(identity);
        }

        #endregion

        protected override void OnReceiveData(int sessionID, int method, ByteArray data)
        {
            base.OnReceiveData(sessionID, method, data);
            switch (method)
            {
                case BattleMethods.CLIENT_LOGONSUCCESS_HASH:
                    OnLogonSuccess();
                    break;
                case BattleMethods.CLIENT_LOGONFAIL_HASH:
                    OnLogonFail(data.ReadUTF());
                    break;
                case BattleMethods.CLIENT_RECEIVERANDOMSEED_HASH:
                    OnReceiveRandomSeed(data.ReadInt());
                    break;
                case BattleMethods.CLIENT_RECEIVEMOVE_HASH:
                    OnReceiveMove(DataByteArray.FromByteArray<PlayerMove>(data));
                    break;
                case BattleMethods.CLIENT_RECEIVETEAM_HASH:
                    OnReceiveTeam(DataByteArray.FromByteArray<BattleTeam>(data));
                    break;
                case BattleMethods.CLIENT_RECEIVERULES_HASH:
                    OnReceiveRules(DataByteArray.ReadArray<BattleRule>(data, t => (BattleRule)t.ReadInt()));
                    break;
                case BattleMethods.CLIENT_RECEIVETIEMESSAGE_HASH:
                    OnReceiveTieMessage(DataByteArray.FromByteArray<TieMessageRequest>(data));
                    break;
                case BattleMethods.CLIENT_EXIT_HASH:
                    OnExit(data.ReadUTF());
                    break;
                case BattleMethods.CLIENT_TIMEUP_HASH:
                    OnTimeUp(data.ReadUTF());
                    break;
                case BattleMethods.CLIENT_REGISTOBSEVER_HASH:
                    OnRegistObsever(data.ReadInt());
                    break;
                case BattleMethods.CLIENT_RECEIVEBATTLEINFO_HASH:
                    OnReceiveBattleInfo(DataByteArray.FromByteArray<BattleInfo>(data));
                    break;
                case BattleMethods.CLIENT_RECEIVEBATTLESNAPSHOT_HASH:
                    OnReceiveBattleSnapshot(DataByteArray.FromByteArray<BattleSnapshot>(data));
                    break;
            }
        }
    }
}
